package com.hmall.item.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.item.domain.dto.ItemDTO;
import com.hmall.item.domain.dto.OrderDetailDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.query.ItemPageQuery;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {
    @Autowired
    private RestHighLevelClient client;

    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            throw new BizIllegalException("更新库存异常，可能是库存不足!", e);
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }
    }

    @Override
    public void addStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateAddStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            throw new BizIllegalException("更新库存异常，可能是库存不足!", e);
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }

    }

/**
 * 搜索商品并返回分页结果
 * @param itemPageQuery 商品分页查询条件，包含关键字、品牌、分类、价格区间、排序方式等信息
 * @return PageDTO<ItemDTO> 包含商品列表、总记录数和总页数的分页结果
 * @throws IOException 可能抛出的IO异常
 */
    @Override
    public PageDTO<ItemDTO> serach(ItemPageQuery itemPageQuery) throws IOException {

        //1.创建请求
        SearchRequest searchRequest = new SearchRequest("hmall");

        //2.设置请求参数(参数 分页 排序 高亮)
        //2.1 参数
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (StrUtil.isBlank(itemPageQuery.getKey())) {//没有传关键字
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {//传了关键字
            boolQuery.must(QueryBuilders.multiMatchQuery(itemPageQuery.getKey(), "name", "brand"));
        }
        //品牌
        if (StrUtil.isNotBlank(itemPageQuery.getBrand())) {
            boolQuery.must(QueryBuilders.termQuery("brand", itemPageQuery.getBrand()));//termQuery 精确查询
        }
        //分类
        if (StrUtil.isNotBlank(itemPageQuery.getCategory())) {
            boolQuery.must(QueryBuilders.termQuery("category", itemPageQuery.getCategory()));//termQuery 精确查询
        }
        //价格区间
        if (itemPageQuery.getMinPrice() != null && itemPageQuery.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price")
                    .lte(itemPageQuery.getMaxPrice())
                    .gte(itemPageQuery.getMinPrice())); //rangeQuery 区间查询
        }
        searchRequest.source().query(boolQuery);//设置查询条件
        //2-4 使用算分函数 提供广告商品的排名
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(boolQuery,
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true),
                                ScoreFunctionBuilders.weightFactorFunction(50))
                }
        );
        searchRequest.source().query(functionScoreQuery);
        //排序
        if (StrUtil.isNotBlank(itemPageQuery.getSortBy())) {
            searchRequest.source().sort(itemPageQuery.getSortBy(), itemPageQuery.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
        }
        //分页
        searchRequest.source().from((itemPageQuery.getPageNo() - 1) * itemPageQuery.getPageSize()).size(itemPageQuery.getPageSize());
        //高亮
        searchRequest.source().highlighter(new HighlightBuilder().field("name").preTags("<em>").postTags("</em>").requireFieldMatch(false));

        //3.发送请求
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        //4.处理结果
        //总记录数
        long total = Objects.requireNonNull(response.getHits().getTotalHits()).value;
        //总页数
        Long pages = total % itemPageQuery.getPageSize() == 0 ?
                (total / itemPageQuery.getPageSize()) : (total / itemPageQuery.getPageSize() + 1);


        // 转换为DTO
        List<ItemDTO> collect = Arrays.stream(response.getHits().getHits()).map(e -> {
            Item item = JSON.parseObject(e.getSourceAsString(), Item.class);
            ItemDTO itemDTO = BeanUtils.copyProperties(item, ItemDTO.class);

            //处理高亮
            Map<String, HighlightField> highlightFields = e.getHighlightFields();
            if (CollUtil.isNotEmpty(highlightFields)) {
                HighlightField highlightField = highlightFields.get("name");
                if (highlightField != null) {
                    itemDTO.setName(highlightField.getFragments()[0].string());
                }
            }
            return itemDTO;
        }).collect(Collectors.toList());

        return new PageDTO<>(total, pages, collect);


    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }
}
